/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of UHM (Unassembled HyperMatrix) sparse direct solver.
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#include "uhm/common.hxx"
#include "uhm/const.hxx"

#include "uhm/object.hxx"

#include "uhm/mesh/node.hxx"
#include "uhm/mesh/element.hxx"

namespace uhm {
  // --------------------------------------------------------------
  // ** Node
  Node_::Node_()                       { _init(std::pair<int,int>(0,0),
					       0, 0, 0); }
  Node_::Node_( std::pair<int,int> id) { _init(id, 0,0,0); }
  Node_::Node_( std::pair<int,int> id, 
		int n_dof, 
		int p, int kind)       { _init(id, n_dof, p, kind); }
  Node_::~Node_()                      { }

  // --------------------------------------------------------------
  void Node_::reset_owner() { this->owner.clear(); }

  void Node_::set_kind    (int kind)   { this->kind = kind; }
  void Node_::set_n_dof   (int n_dof)  { this->n_dof = n_dof; }
  void Node_::set_p       (int p)      { this->p = p; }
  void Node_::set_offset  (int offset) { this->offset = offset; }
  void Node_::set_marker  (int marker) { this->marker = marker; }

  int  Node_::get_kind()   { return this->kind; }
  int  Node_::get_n_dof()  { return this->n_dof; }
  int  Node_::get_p()      { return this->p; }
  int  Node_::get_n_owner(){ return this->owner.size(); }
  int  Node_::get_offset() { return this->offset; }
  int  Node_::get_marker() { return this->marker; }

  bool Node_::is_owned_by(Element e) {
    assert(element_valid(e));
    return (this->owner.end() != this->owner.find(e));
  }

  bool Node_::is_same_as(Node n) {
    assert(node_valid(n));

    return ( (this->get_id()    == n->get_id()) &&
	     (this->get_n_dof() == n->get_n_dof()) &&
	     (this->get_kind()  == n->get_kind()) &&
	     (this->get_p()     == n->get_p()) );
  }

  void Node_::add_owner(Element e) {
    assert(element_valid(e));

#pragma omp critical
    this->owner.insert(e);

  }

  void Node_::remove_owner(Element e) {
    assert(element_valid(e));

#pragma omp critical
    this->owner.erase( this->owner.find(e) );

  }

  void Node_::clean_connectivity() {
    // if owner is not leaf, erase it 
    std::vector< std::set< Element >::iterator > tmp;
    tmp.reserve(this->owner.size());

#pragma omp critical
    {
      {
        std::set< Element >::iterator it;
        for (it=this->owner.begin();it!=this->owner.end();++it) 
          if (!(*it)->is_leaf()) 
            tmp.push_back(it);
      }
      {
        std::vector< std::set< Element >::iterator >::iterator it;
        for (it=tmp.begin();it!=tmp.end();++it)
          this->owner.erase(*it);
      }
    }

// #pragma omp critical
//     {
//       std::set< Element >::iterator it;
//       for (it=this->owner.begin();it!=this->owner.end();++it)
//         if (!(*it)->is_leaf()) this->owner.erase(it);
//     }


  }

  bool Node_::disp() { return this->disp(stdout); }
  bool Node_::disp(FILE *stream) {
    fprintf(stream, " - Node -\n");
    fprintf(stream, "  id [ %d , %d ] , offset [ %d ], ",
	    this->get_id().first, this->get_id().second,
	    this->get_offset() );
    fprintf(stream, "n_dof [ %d ], kind [ %d ], poly [ %d ]\n", 
	    this->get_n_dof(), this->get_kind(), this->get_p());

    if (this->get_n_owner()) {
      fprintf(stream, "  %d owners [ ", this->get_n_owner());
      
      std::set< Element >::iterator it;
      for (it=this->owner.begin();it!=this->owner.end();it++) 
	fprintf(stream, " %d ", (*it)->get_id());
      fprintf(stream, " ]\n");

    }
    return true;
  }
}
